package com.xtm.exercise.base.A14Singleton;

import org.junit.Test;

/*
          单例设计模式
             1、设计模式
                 结局某类问题行之有效的方法，是一种思想，是规律的总结
             2、用来保证某个类在内存中只有一个对象
             3、保证唯一性的思想及步骤
                 1)、为避免其他程序建立该类对象，先禁止其他程序建立该类对象，即将构造函数私有化
                 2)、为了其他程序访问到该类对象，须在本类中创建一个该类私有对象
                 3)、为了方便其他程序访问到该类对象，可对外提供一个公共访问方式
                 4)、单例设计模式的两种方式
                      饿汉模式当类加载的时候，就创建对象
                      懒汉模式当使用的时候，才去创建对象
                 5)、饿汉模式和懒汉模式的区别
                      a、饿汉模式是类一加载进内存就创建好了对象
                      b、懒汉模式则是类才加载进内存的时候，对象还没有存在，调用getinstance方法时，对象才开始创建
                      c、懒汉模式是延迟加载，如果多各线程同时操作懒汉模式时就有可能出现线程安全问题
                      解决线程安全问题:可以加同步来解决，但是加了同步之后，每一次都要比较锁，效率就变慢了，所有可以加双重判断来提高程序效率
                      备注：开发常用饿汉模式，因为饿汉模式简单安全，懒汉模式多线程的时候容易出问题

 **/
public class TestDemo {

    /**
     * 饿汉式
     * 运行结果：
     *   abc.test.Son@15db9742
     *   abc.test.Son@15db9742
     */
    @Test
    public void sonSingleton(){
        Son s1 = Son.getInstance();
        Son s2 = Son.getInstance();
        System.out.println(s1);
        System.out.println(s2);
    }

    /**
     懒汉式和饿汉式的安全和性能区别：

     （1） 线程安全：饿汉式在线程还没出现之前就已经实例化了，所以饿汉式一定是线程安全的。懒汉式加载是在使用时才会去new 实例的，那么你去new的时候是一个动态的过程，是放到方法中实现的，比如：

     public static synchronized Singleton getInstance(){
     　　 if(instance == null){
     　　　　　//什么时候用就什么时候new
     　　instance = new Singleton();
     　　 }

     如果这个时候有多个线程访问这个实例，这个时候实例还不存在，还在new，就会进入到方法中，有多少线程就会new出多少个实例。一个方法只能return一个实例，那最终return出哪个呢？是不是会覆盖很多new的实例？这种情况当然也可以解决，那就是加同步锁，避免这种情况发生 。

     （2）执行效率：饿汉式没有加任何的锁，因此执行效率比较高。懒汉式一般使用都会加同步锁，效率比饿汉式差。
     （3）内存使用：饿汉式在一开始类加载的时候就实例化，无论使用与否，都会实例化，所以会占据空间，浪费内存。懒汉式什么时候用就什么时候实例化，不浪费内存。
    **/
    /**
     * 懒汉式
     * 运行结果：
     *     abc.test.Girl@15db9742
     *     abc.test.Girl@15db9742
     *     abc.test.Girl@15db9742
     *     abc.test.Girl@15db9742
     */
    @Test
    public void girlSingleton(){
        //一个线程对象的时候，线程安全的
        Girl g1 = Girl.getInstance();
        Girl g2 = Girl.getInstance();
        System.out.println(g1);
        System.out.println(g2);
        //多个线程对象的时候，线程不安全
        new Thread(){
            public void run(){
                Girl g = Girl.getInstance();
                System.out.println(g);
            }
        }.start();

        new Thread(){
            public void run(){
                Girl g = Girl.getInstance();
                System.out.println(g);
            }
        }.start();
    }
}
